home *** CD-ROM | disk | FTP | other *** search
/ Mac Magazin/MacEasy 24 / Mac Magazin and MacEasy Magazine CD - Issue 24.iso / Wissenschaft & Technik / ProgressCDEF ƒ / ProgressCDEF.c < prev    next >
C/C++ Source or Header  |  1996-06-22  |  15KB  |  475 lines

  1. // ***********************************************************************************
  2.  
  3. //    ProgressCDEF © Andrew Regan, 1996 (Andrew_G.D._Regan@iconex.mactel.org)
  4.  
  5. //    ProgressCDEF is substantially based upon FinderProgressBar 2.0 (which is © Chris Larson)
  6. //    but features substantial alterations made by me: considerable additions, improvement
  7. //    of existing features, a general cleaning-up, and the cutting of a couple of irrelevancies.
  8.  
  9. //    Conditions – I quote from Chris Larson's original terms:
  10. //    " ... Source file of a CDEF which mimics the progress bar used in the Finder.
  11. //    This source file and its compiled derivatives may be freely used within any
  12. //    freeware/shareware/postcardware/beerware/… as long as you mention my name
  13. //    in your credits. Neither this source nor its compiled derivatives are
  14. //    in the public domain and may not be use in any form in public domain software.
  15. //    Neither this source nor its compiled derivatives may be used in any form in a
  16. //    commercial product without the expressed, written consent of the author (me)... "                                                               *
  17.  
  18. //    I ask no money for the use of ProgressCDEF, as my interest in distributing it is
  19. //    as a service to others: to improve the quality of shareware software, etc.
  20. //    Hopefully it will drive several inferior products out of the market.
  21.  
  22. //    ***********************************************************************************/
  23.  
  24. #ifndef    powerc
  25. #include <A4Stuff.h>
  26. #endif
  27.  
  28. #include "Gestalt.h"
  29. #include "Palettes.h"
  30.  
  31. #define    kIsColorPort        0xC000
  32. #define    kBarberStripeWidth    8
  33. #define kFPBFrameCount        16        // The number of frames in the “Barber Pole” animation loop.
  34.  
  35. void        GetWctbColor(        WindowPtr w, RGBColor *lite, RGBColor *dark, long rc, short variation);
  36. pascal long main(                short varCode, ControlRef theControlHandle, short message, long param);
  37. void        BeginDraw(            ControlRef theControlHandle, short varCode);
  38. RGBColor*    FindColorInTable(    WCTabHandle colorTable, short id);
  39. void        DrawNormalBar(        ControlPtr theControl, RGBColor *barColor, RGBColor *bodyColor, short col);
  40. void        DrawBarberPoleBar(    ControlPtr theControl, RGBColor *barColor, RGBColor *bodyColor, short col);
  41.  
  42. #ifdef    powerc
  43.     short CalculateBarBoundry( short boxLeft, short boxRight, ControlPtr theControl);
  44. #else
  45.     asm short CalculateBarBoundry( short boxLeft, short boxRight, ControlPtr theControl);
  46. #endif
  47.  
  48.  
  49. static const RGBColor    gBlackColor = {0,0,0}, midGrey = {32767,32767,32767};
  50.  
  51.  
  52. /*******************************************************************************
  53.  
  54.     ••• main •••
  55.  
  56. *******************************************************************************/
  57. pascal long main( short varCode, ControlHandle theControlHandle, short message, long param)
  58. {
  59.     ControlPtr    theControl;
  60.     SignedByte    controlRecState;
  61.     long        returnValue;
  62.  
  63.  
  64.     #ifndef    powerc
  65.         long    oldA4 = SetCurrentA4();
  66.     #endif
  67.  
  68.     controlRecState = HGetState( (Handle) theControlHandle);
  69.     HLock( (Handle) theControlHandle);
  70.  
  71.     returnValue = 0;
  72.     theControl = *theControlHandle;
  73.  
  74.     switch (message)
  75.     {
  76.         case drawCntl:
  77.             if ( theControl->contrlVis)        BeginDraw( theControlHandle, varCode);
  78.             break;
  79.         case testCntl:
  80.             if ( PtInRect( *(Point*)(¶m), &(theControl->contrlRect)) )        returnValue = 50;
  81.             break;
  82.         case calcCRgns:        param &= 0x7FFFFFFF;
  83.         case calcCntlRgn:
  84.             RectRgn( (RgnHandle) param, &(theControl->contrlRect));
  85.             break;
  86.         default:            break;
  87.     }
  88.  
  89.     HSetState( (Handle) theControlHandle, controlRecState);
  90.  
  91.     #ifndef    powerc
  92.         SetA4(oldA4);
  93.     #endif
  94.  
  95.     return returnValue;
  96. }
  97.  
  98.  
  99. /*******************************************************************************
  100.  
  101.     ••• BeginDraw •••
  102.  
  103.     Save off all the stuff we’re going to change, figure out which colors to use (and
  104.     whether we need to dither) and call the appropriate drawing routine.
  105.  
  106. *******************************************************************************/
  107. void BeginDraw( ControlRef c, short varCode)
  108. {
  109.     AuxWinHandle    awh;
  110.     RgnHandle        rgn, oldClip;
  111.     ControlPtr        theControl = *c;
  112.     GrafPtr            savePort, g = theControl->contrlOwner;
  113.     RGBColor        oldFore, oldBack, windowBack;
  114.     RGBColor        frameColor = gBlackColor, barColor, bodyColor;
  115.     Pattern            pat;
  116.     PenState        oldPen;
  117.     Rect            theBox = theControl->contrlRect;
  118.     long            rc = theControl->contrlRfCon;
  119.     short            useColor;
  120.     Boolean            doDither = false;
  121.  
  122.  
  123.     GetPort(&savePort);
  124.     SetPort(g);
  125.  
  126.     /*    Determine if Color Quickdraw exists and should be used. Actually,
  127.         this simply looks to see if the control’s owning port is a color port. If so, it infers
  128.         the existence of CQD and uses it. If not, we’re drawing into a B/W port anyway, so who
  129.         cares if CQD is present?    */
  130.  
  131.     useColor = (((g->portBits.rowBytes) & kIsColorPort) == kIsColorPort);
  132.  
  133.     GetIndPattern( &pat, 0, 4);
  134.     GetPenState(&oldPen);
  135.     PenNormal();
  136.  
  137.     if (useColor)
  138.     {
  139.         GetForeColor(&oldFore);
  140.         GetBackColor(&oldBack);
  141.         
  142.         GetWctbColor( g, &bodyColor, &barColor, rc, varCode);
  143.  
  144.         //    Retrieve the window content color (background color) of the control’s owner.
  145.  
  146.         GetAuxWin( g, &awh);
  147.         windowBack = *FindColorInTable( (WCTabHandle) (*awh)->awCTable, wContentColor);
  148.     }
  149.  
  150.     if ( theControl->contrlHilite == kControlInactiveControlPart)
  151.     {
  152.         if ( varCode < 8)    doDither = true;
  153.     }
  154.  
  155.     //    Draw the bar’s frame. Since this is always the same and will always lie within the control’s
  156.     //    rectangle (thus making the clipping region mind the control’s rectangle would have no effect)
  157.     //    we can do it here, before mucking with the clipping region.
  158.  
  159.     if (useColor)
  160.     {
  161.         if (doDither)        RGBForeColor(&midGrey);
  162.         else                RGBForeColor(&frameColor);
  163.         RGBBackColor(&windowBack);
  164.     }
  165.     else
  166.     {
  167.         if (doDither)        PenPat(&pat);
  168.     }
  169.  
  170.     FrameRect(&theBox);
  171.     InsetRect( &theBox, 1, 1);
  172.  
  173.     if (doDither)            PenNormal();
  174.  
  175.     //    Save the current port’s clip region and set it to the intersection of the clip region with
  176.     //    the newly inset rectangle (so it won’t allow overwriting of the freshly drawn frame).
  177.  
  178.     oldClip = NewRgn();
  179.     GetClip(oldClip);
  180.  
  181.     rgn = NewRgn();        RectRgn( rgn, &theBox);            SectRgn( rgn, oldClip, rgn);
  182.     SetClip(rgn);        DisposeRgn(rgn);
  183.  
  184.     //    Figure out if we are supposed to draw the “Barber Pole” or the regular bar.
  185.     //    In that case, take the frame number from
  186.     //    the low word of the RfCon. Frames are numbered from 0 to ( kFPBFrameCount - 1 ), inclusive.
  187.  
  188.     //    variation codes:
  189.     //    1        = do not colour according to tinges
  190.     //    >= 8    = do not dim
  191.     //    refCon >= 1000    = draw BarberPole
  192.  
  193.     if ( rc >= 1000)
  194.     {
  195.         DrawBarberPoleBar( theControl, &barColor, &bodyColor, useColor);
  196.     }
  197.     else        DrawNormalBar( theControl, &barColor, &bodyColor, useColor);
  198.  
  199.     //    Dither the progress bar if we’re supposed to
  200.  
  201.     if (doDither)
  202.     {
  203.         if (useColor)        RGBBackColor(&windowBack);
  204.         PenMode(notPatBic);
  205.         PenPat(&pat);
  206.         PaintRect(&theControl->contrlRect);
  207.     }
  208.  
  209.     if (useColor)
  210.     {
  211.         RGBForeColor(&oldFore);
  212.         RGBBackColor(&oldBack);
  213.     }
  214.  
  215.     SetPenState(&oldPen);
  216.  
  217.     SetClip(oldClip);
  218.     DisposeRgn(oldClip);
  219.  
  220.     SetPort(savePort);
  221. }
  222.  
  223.  
  224. /*******************************************************************************
  225.  
  226.     ••• DrawNormalBar •••
  227.  
  228.     Draw the progress bar according to the control settings using the colors given
  229.     in the parameters.
  230.  
  231. *******************************************************************************/
  232. void DrawNormalBar( ControlPtr theControl, RGBColorPtr barColor, RGBColorPtr bodyColor, short useColor)
  233. {
  234.     Rect    theBox = theControl->contrlRect;
  235.  
  236.     InsetRect( &theBox,1,1);
  237.     theBox.right = CalculateBarBoundry( theBox.left, theBox.right, theControl);
  238.  
  239.     //    Set up colors so that the bar will map to black on a 1-bit device; then draw the bar.
  240.  
  241.     if (useColor)
  242.     {
  243.         RGBForeColor(barColor);
  244.         BackColor(30);
  245.     }
  246.  
  247.     PaintRect(&theBox);
  248.  
  249.     //    Now set up theBox to draw the “empty” space not yet filled by the bar.
  250.  
  251.     theBox.left = theBox.right;
  252.     theBox.right = theControl->contrlRect.right - 1;
  253.  
  254.     //    Set up colors so that the space will map to white on a 1-bit device; then draw the space.
  255.  
  256.     if (useColor)
  257.     {
  258.         RGBForeColor(bodyColor);
  259.         BackColor(33);
  260.     }
  261.     else        PenMode(patBic);
  262.  
  263.     PaintRect(&theBox);
  264. }
  265.  
  266.  
  267. /*******************************************************************************
  268.  
  269.     ••• DrawBarberPoleBar •••
  270.  
  271. *******************************************************************************/
  272. void DrawBarberPoleBar( ControlPtr theControl, RGBColor *barColor, RGBColor *bodyColor, short useColor)
  273. {
  274.     Rect    theBox = theControl->contrlRect;
  275.     short    i, height, frameNumber;
  276.  
  277.  
  278.     InsetRect( &theBox, 1, 1);
  279.     PenSize( kBarberStripeWidth, 1);
  280.  
  281.     //    Set up the colors. On a 1-bit device, one of these should map to white and the other black. It
  282.     //    doesn’t _really_ matter which maps to which as long as they’re different.
  283.  
  284.     if (useColor)
  285.     {
  286.         RGBForeColor(barColor);
  287.         RGBBackColor(bodyColor);
  288.     }
  289.  
  290.     //    Compute the horizontal starting point for drawing. Note that each drawing loop draws one
  291.     //    stripe of each color (with grey drawn first). This starting point is set far enough to the
  292.     //    left to make the first set of stripes drawn hit the lower left corner of the bar.
  293.  
  294.     height = theBox.bottom - theBox.top;
  295.     frameNumber = theControl->contrlValue % kFPBFrameCount;
  296.  
  297.     i = height + frameNumber + 2 * kBarberStripeWidth - 2;
  298.     i = i / ( 2 * kBarberStripeWidth );
  299.     i = theBox.left - i * 2 * kBarberStripeWidth + frameNumber;
  300.  
  301.     //    Now back bias the starting location to account for the first increment.
  302.  
  303.     i -= kBarberStripeWidth;
  304.  
  305.     //    Until we would start drawing to the right of the bar, draw a pair of lines, slanting to the
  306.     //    right, first of the two in the bar color, second in the fill color.
  307.  
  308.     while ( i < theBox.right)
  309.     {
  310.         i += kBarberStripeWidth;
  311.         PenMode(patCopy);
  312.         MoveTo( i, theBox.top);
  313.         LineTo( i + height, theBox.bottom - 1);
  314.  
  315.         i += kBarberStripeWidth;
  316.         PenMode(patBic);
  317.         MoveTo( i, theBox.top);
  318.         LineTo( i + height, theBox.bottom - 1);
  319.     }
  320. }
  321.  
  322.  
  323. /*******************************************************************************
  324.  
  325.     ••• CalculateBarBoundry •••
  326.  
  327.     Given the edges of the progress bar and the control’s setting, determine
  328.     where the right edge of the progress bar belongs.
  329.     On the PowerPC architecture, this is implemented in C; while on the 680x0
  330.     it is implemented in assembly. This is done because the 68000 does not
  331.     support 32-bit multiplies in hardware, 32-bit multiplies are not strictly
  332.     necessary (the 16->32 multiply and 32->16 divide will suffice), and the
  333.     compiler was not using the mulu.w and divu.w instructions correctly. (Well,
  334.     it was using them correctly in the C sense, but that’s not what I wanted
  335.     them to do.)
  336.  
  337. *******************************************************************************/
  338. #ifdef    powerc
  339.  
  340. short CalculateBarBoundry(short boxLeft, short boxRight, ControlPtr theControl)
  341. {
  342.     short    result = boxLeft;
  343.     short    min = theControl->contrlMin;
  344.     short    max = theControl->contrlMax;
  345.     short    val = theControl->contrlValue;
  346.     long    top = ( boxRight - boxLeft ) * ( val - min );
  347.     long    bottom = max - min;
  348.  
  349.     if ( bottom != 0 )        result += top / bottom;
  350.     return result;
  351. }
  352.  
  353. #else
  354.  
  355.  
  356. /*******************************************************************************
  357.  
  358.     ••• CalculateBarBoundry •••
  359.  
  360.     A couple of notes about the assembly language. This method will calculate the correct answer no
  361.     matter what values are given as long as the following conditions hold:
  362.         (1) boxRight >= boxLeft, and
  363.         (2) contrlMax >= contrlValue >= contrlMin.
  364.     Both of these should be met in normal circumstances. If these restrictions hold, then the
  365.     differences (both in the numerator and the one in the denominator) will fit into 16-bit unsigned
  366.     integers. That means that I can use the mulu.w and divu.w instructions to perform the multiply
  367.     and divide, instead of requiring the addition of the software library for 32 bit multiplication
  368.     on the 68000 (The software library was twice the size of this code resource last time I checked).
  369.     The only other thing to note is that a division by zero can’t happen. The denominator is zero
  370.     only when contrlMax == contrlMin. If this is the case, then contrlValue == contrlMin and the
  371.     branch before the multiply will be taken, so the division instruction is never reached.
  372.  
  373. *******************************************************************************/
  374. asm short CalculateBarBoundry(short boxLeft, short boxRight, ControlPtr theControl)
  375. {
  376.     fralloc                                                // Give ourselves a stack frame
  377.  
  378.     move.w    boxRight,d1                                    // Right edge of the box to d1
  379.     move.w    boxLeft,d0                                    // Left edge of the box to d0
  380.     sub.w    d0,d1                                        // Width of the box to d0
  381.  
  382.     movea.l    theControl,a0                                // Store the control pointer in a0
  383.     move.w    struct (ControlRecord.contrlValue)(a0),d2    // Control’s value to d2
  384.     sub.w    struct (ControlRecord.contrlMin)(a0),d2        // Normalized value to d2
  385.  
  386.     beq        @1                                            // If normalized value == 0, exit. (Note
  387.                                                         //    that d0 already holds left edge)
  388.  
  389.     mulu.w    d2,d1                                        // box width * normalized value to d1
  390.  
  391.     move.w    struct (ControlRecord.contrlMax)(a0),d2        // Control’s max to d2
  392.     sub.w    struct (ControlRecord.contrlMin)(a0),d2        // Normalized maximum to d2
  393.  
  394.     divu.w    d2,d1                                        // width * value / maximum to d1. Note that
  395.                                                         //    divide by zero can’t happen here.
  396.  
  397.     add.w    d1,d0                                        // Offset left edge by amount in d1
  398.  
  399.  @1:
  400.     frfree                                                // Remove the stack frame
  401.     rts                                                    // Outa here...
  402. }
  403.  
  404. #endif
  405.  
  406.  
  407. /*******************************************************************************
  408.  
  409.     ••• FindColorInTable •••
  410.  
  411.     Return a pointer to the RGBColor matching the given id. Return the first entry
  412.     in the table if none match. Note that this routine will not cause memory to
  413.     move, but since it returns a pointer which references a handle’s block, one
  414.     must be sure to lock the handle if the pointer is going to be used in or
  415.     after a call that may move memory (like RGBForeColor() or RGBBackColor()).
  416.  
  417. *******************************************************************************/
  418. RGBColor* FindColorInTable( WCTabHandle colorTable, short id)
  419. {
  420.     short    i;
  421.  
  422.     for ( i = (*colorTable)->ctSize; i != 0; i--)
  423.     {
  424.         if ( (*colorTable)->ctTable[i].value == id )        break;
  425.     }
  426.  
  427.     return ( &( (*colorTable)->ctTable[i].rgb ));
  428. }
  429.  
  430.  
  431. /*******************************************************************************
  432.  
  433.     ••• GetWctbColor •••
  434.  
  435. *******************************************************************************/
  436. void GetWctbColor( WindowPtr w, RGBColor *lite, RGBColor *dark, long rc, short variation)
  437. {
  438.     AuxWinHandle    awHndl;
  439.     OSErr            err = 1;
  440.     long            gestaltResponse;
  441.     short            count, dk = 0x4444;
  442.     Boolean            makeBlack = false, useAaron;
  443.  
  444.  
  445.     GetAuxWin( w, &awHndl); 
  446.     count = (*(WCTabHandle) ((*awHndl)->awCTable))->ctSize;
  447.  
  448.     if ( count < 11)    // must have at least wTingeLight
  449.     {
  450.         GetAuxWin( nil, &awHndl); 
  451.         count = (*(WCTabHandle) ((*awHndl)->awCTable))->ctSize;
  452.     }
  453.             
  454.     err = Gestalt( 'Aarn', &gestaltResponse);
  455.     useAaron = (( err == noErr) && ( rc < 1000));
  456.  
  457.     if (( count < 11) || ( variation == 1) || useAaron)
  458.     {
  459.         lite->red = lite->green = 0xCCCC;        // defaults when ~Aaron installed
  460.         lite->blue = 0xFFFF;
  461.     }
  462.     else
  463.     {
  464.         *lite = (*(WCTabHandle) ((*awHndl)->awCTable))->ctTable[11].rgb;    // wTingeLight
  465.         if (( lite->red == lite->green) && ( lite->green == lite->blue) && ( lite->blue == 0))
  466.         {
  467.             lite->red = lite->green = lite->blue = 0xFFFF;
  468.             makeBlack = true;
  469.         }
  470.     }
  471.  
  472.     if ( err != noErr)        ++dk;
  473.     if (makeBlack)            dk = 0;
  474.     dark->red = dark->green = dark->blue = dk;
  475. }